#include <SDL3/SDL.h>
#include <SDL3_image/SDL_image.h>
#include <filesystem>
#include <deque>
using namespace std::filesystem;
#define PICTURE_SIZE 4
#define WINDOW_SIZE 800
#define PICTURE_WIDTH WINDOW_SIZE / PICTURE_SIZE
int array[PICTURE_SIZE][PICTURE_SIZE] = {0};
int blank_x = 0;
int blank_y = 0;
int game_over()
{
    for (int i = 0; i < PICTURE_SIZE; i++)
    {
        for (int j = 0; j < PICTURE_SIZE; j++)
        {
            if (array[i][j] != i * PICTURE_SIZE + j)
            {
                return 0; // 游戏未结束
            }
        }
    }
    SDL_Log("Game over!");
    return 1; // 游戏结束
}
/**
 * * @brief 交换相交空白块函数
 * * @param mouse_x 按钮的 x 坐标
 * * @param mouse_y 按钮的 y 坐标
 */
void swapBlank(float mouse_x, float mouse_y)
{
    SDL_Log("Mouse button down at (%f, %f)", mouse_x, mouse_y);
    // 计算点击位置的 x 坐标和 y 坐标
    int width = PICTURE_WIDTH;
    int x = (int)(mouse_x / width); // 计算点击位置的 x 坐标
    int y = (int)(mouse_y / width); // 计算点击位置的 y 坐标
    if (x < 0 || x >= PICTURE_SIZE || y < 0 || y >= PICTURE_SIZE)
    {
        SDL_Log("Clicked out of bounds at (%d, %d)", x, y);
        return; // 点击位置不在范围内
    }
    if (array[x][y] == PICTURE_SIZE * PICTURE_SIZE - 1)
    {
        SDL_Log("Clicked on blank block at (%d, %d)", x, y);
        return; // 点击的是空白块
    }
    // 判断点击位置是否和空白块相邻
    if ((x == blank_x && (y == blank_y - 1 || y == blank_y + 1)) || (y == blank_y && (x == blank_x - 1 || x == blank_x + 1)))
    {
        SDL_Log("Clicked on adjacent block at (%d, %d)", x, y);
        // 交换空白块和点击位置的块
        std::swap(array[blank_x][blank_y], array[x][y]);
        blank_x = x;
        blank_y = y;
        return;
    }
}
/**
 * * @brief 绘制拼图纹理函数
 * * @param renderer 渲染器对象
 * * @param texture 纹理对象
 */
void drawTexture(SDL_Renderer *renderer, SDL_Texture *texture)
{
    SDL_FRect src_rect = {0, 0, (float)texture->h, (float)texture->w}; // x, y, width, height
    SDL_FRect dst_rect = {0, 0, 200, 200};
    for (int i = 0; i < PICTURE_SIZE; i++)
    {
        for (int j = 0; j < PICTURE_SIZE; j++)
        {
            if (array[i][j] == PICTURE_SIZE * PICTURE_SIZE - 1)
            {
                continue; // 跳过空白块
            }
            // 计算纹理的目标矩形位置顶点(依次绘制每个小块)
            dst_rect.x = i * (float)PICTURE_WIDTH;
            dst_rect.y = j * (float)PICTURE_WIDTH;
            dst_rect.w = PICTURE_WIDTH;
            dst_rect.h = PICTURE_WIDTH;
            // 计算纹理的源矩形位置顶点
            src_rect.x = (array[i][j] / PICTURE_SIZE) * (float)(texture->w / PICTURE_SIZE);
            src_rect.y = (array[i][j] % PICTURE_SIZE) * (float)(texture->h / PICTURE_SIZE);
            // 纹理大小
            src_rect.w = (float)texture->w / (float)PICTURE_SIZE;
            src_rect.h = (float)texture->h / (float)PICTURE_SIZE;
            SDL_RenderTexture(renderer, texture, &src_rect, &dst_rect);
        }
    }
}
/**
 * * @brief 主循环函数
 * * @param renderer 渲染器对象
 * * @param texture 纹理对象
 */
void mainLoop(SDL_Renderer *renderer, SDL_Texture *texture)
{
    SDL_Event event;
    float src_height = (float)texture->h;
    float src_width = (float)texture->w;
    bool running = true;
    SDL_FRect src_rect = {0, 0, (float)texture->h, (float)texture->w}; // x, y, width, height
    SDL_FRect dst_rect = {0, 0, 200, 200};
    while (running)
    {
        while (SDL_PollEvent(&event))
        {
            if (event.type == SDL_EVENT_QUIT)
            {
                running = false;
            }
            if (event.type == SDL_EVENT_MOUSE_BUTTON_DOWN)
            {
                SDL_Log("Mouse button down at (%f, %f)", event.button.x, event.button.y);
                // SDL_Log("%d",event.button.clicks);
                // SDL_Log("Mouse button %d clicked", event.button.button);
                swapBlank(event.button.x, event.button.y); // 交换空白块
                int ret = game_over();                     // 检查游戏是否结束
                if (ret == 1)
                {
                    running = false;
                }
                // 计算点击位置
                // float x = event.button.x / (WINDOW_SIZE / PICTURE_SIZE);
                // float y = event.button.y / (WINDOW_SIZE / PICTURE_SIZE);
                // // 计算纹理的源矩形
                // src_rect.x = x * (texture->w / PICTURE_SIZE);
                // src_rect.y = y * (texture->h / PICTURE_SIZE);
                // src_rect.w = (float)texture->w / (float)PICTURE_SIZE;
                // src_rect.h = (float)texture->h / (float)PICTURE_SIZE;
                SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
                SDL_RenderClear(renderer);
                drawTexture(renderer, texture);
                SDL_RenderPresent(renderer);
                SDL_Delay(10);
            }
        }
        SDL_Delay(100);
        SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
        SDL_RenderClear(renderer);
        drawTexture(renderer, texture);
        SDL_RenderPresent(renderer);
        // SDL_RenderTexture(renderer, texture, &src_rect, &dst_rect);
        // SDL_RenderPresent(renderer);
    }
}
/**
 * * @brief 释放资源函数
 * * @param texture 纹理对象
 * * @param renderer 渲染器对象
 * * @param window 窗口对象
 */
void destroyResource(SDL_Texture *texture, SDL_Renderer *renderer, SDL_Window *window)
{
    SDL_DestroyTexture(texture);
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();
}
/**
 * * @brief 主函数
 * * @param argc 参数个数
 * * @param argv 参数数组
 * * @return int 返回值
 */
int main(int argc, char *argv[])
{
    std::deque<int> deque(PICTURE_SIZE * PICTURE_SIZE);
    for (int i = 0; i < PICTURE_SIZE * PICTURE_SIZE; i++)
    {
        deque.push_back(i);
    }
    for (int i = 0; i < PICTURE_SIZE; i++)
    {
        for (int j = 0; j < PICTURE_SIZE; j++)
        {
            array[i][j] = deque.back();
            deque.pop_back();
            if (array[i][j] == PICTURE_SIZE * PICTURE_SIZE - 1)
            {
                // 空白块
                blank_x = i;
                blank_y = j;
            }
        }
    }

    SDL_Init(SDL_INIT_VIDEO);
    auto window = SDL_CreateWindow("拼图游戏", WINDOW_SIZE, WINDOW_SIZE, SDL_WINDOW_OPENGL);
    if (window == nullptr)
    {
        SDL_Log("Failed to create window: %s", SDL_GetError());
        return -1;
    }
    std::filesystem::path exe_path = path(argv[0]).remove_filename();
    std::string BasePath = SDL_GetBasePath();
    SDL_Log("BasePath: %s", BasePath.c_str());
    std::filesystem::path path = exe_path / "resources/picture.jpg";
    // 设置窗口图标
    std::filesystem::path icon_path = exe_path / "resources/picture.ico";
    auto icon = IMG_Load(icon_path.string().c_str());
    if (icon == nullptr)
    {
        SDL_Log("Failed to load icon: %s", SDL_GetError());
        return -1;
    }
    SDL_SetWindowIcon(window, icon);
    auto surface = IMG_Load(path.string().c_str());
    if (surface == nullptr)
    {
        SDL_Log("Failed to load picture: %s", SDL_GetError());
        return -1;
    }
    auto renderer = SDL_CreateRenderer(window, nullptr);
    if (renderer == nullptr)
    {
        SDL_Log("Failed to create renderer: %s", SDL_GetError());
        return -1;
    }
    // 转换为纹理
    auto texture = SDL_CreateTextureFromSurface(renderer, surface);
    if (texture == nullptr)
    {
        SDL_Log("Failed to create texture: %s", SDL_GetError());
        return -1;
    }
    int height = surface->h;
    int width = surface->w;
    SDL_DestroySurface(surface); // 立即释放 Surface
    // 事件循环
    mainLoop(renderer, texture);
    // 清理资源
    destroyResource(texture, renderer, window);
    return 0;
}